import pandas as pd
import numpy as np
from pyecharts import options as opts
from pyecharts.charts import Bar, Pie, Line, Grid, Boxplot, HeatMap, Tab, Radar


# 年龄分布柱状图
def age_distribution_bar(data):
    age_counts = data['age'].value_counts().sort_index()
    bar = (
        Bar()
        .add_xaxis(age_counts.index.astype(str).tolist())
        .add_yaxis("人数", age_counts.values.tolist())
        .set_global_opts(
            title_opts=opts.TitleOpts(title="年龄分布"),
            xaxis_opts=opts.AxisOpts(name="年龄"),
            yaxis_opts=opts.AxisOpts(name="人数"),
            datazoom_opts=[opts.DataZoomOpts()]
        )
    )
    return bar


# 患病人群性别比例饼图
def gender_disease_pie(data):
    disease_data = data[data['cardio'] == 1]
    gender_counts = disease_data['gender'].value_counts()
    pie = (
        Pie()
        .add("", [list(z) for z in zip(gender_counts.index.tolist(), gender_counts.values.tolist())])
        .set_global_opts(title_opts=opts.TitleOpts(title="患病人群性别分布"))
        .set_series_opts(
            label_opts=opts.LabelOpts(formatter="{b}: {c} ({d}%)")
        )
    )
    return pie


# 年龄组心脏病患病率
def cardio_rate_by_age_group(data):
    bins = [30, 40, 50, 60, 70]
    labels = ['30-39', '40-49', '50-59', '60-69']
    data['age_group'] = pd.cut(data['age'], bins=bins, labels=labels)
    # group = data.groupby('age_group')['cardio'].mean().reset_index()
    group = data.groupby('age_group', observed=False)['cardio'].mean().reset_index()
    line = (
        Line()
        .add_xaxis(group['age_group'].astype(str).tolist())
        .add_yaxis("患病率(%)", (group['cardio'] * 100).round(2).tolist())
        .set_global_opts(
            title_opts=opts.TitleOpts(title="不同年龄组心脏病患病率"),
            xaxis_opts=opts.AxisOpts(name="年龄组"),
            yaxis_opts=opts.AxisOpts(name="患病率(%)")
        )
    )
    return line


# 健康状况指标
def health_indicators_analysis(data):
    """血压分组分析"""
    data['hypertension'] = '正常'
    data.loc[(data['ap_hi'] >= 140) | (data['ap_lo'] >= 90), 'hypertension'] = '高血压'
    bp_group = data.groupby('hypertension')['cardio'].mean().reset_index()
    bp_group['cardio'] = bp_group['cardio'] * 100
    bp_bar = (
        Bar()
        .add_xaxis(bp_group['hypertension'].tolist())
        .add_yaxis("患病率(%)", bp_group['cardio'].round(1).tolist())
        .set_global_opts(
            title_opts=opts.TitleOpts(title="高血压组 vs 正常组的心脏病患病率"),
            yaxis_opts=opts.AxisOpts(name="患病率(%)", max_=100),
            tooltip_opts=opts.TooltipOpts(formatter="{b}: {c}%")
        )
    )

    """胆固醇等级分析"""
    chol_map = {1: "正常", 2: "偏高", 3: "严重偏高"}
    data['cholesterol_label'] = data['cholesterol'].map(chol_map)
    chol_group = data.groupby('cholesterol_label')['cardio'].mean().reset_index()
    chol_group['cardio'] = chol_group['cardio'] * 100
    ordered_labels = ['正常', '偏高', '严重偏高']
    chol_group = chol_group.set_index('cholesterol_label').reindex(ordered_labels).reset_index()
    chol_bar = (
        Bar()
        .add_xaxis(chol_group['cholesterol_label'].tolist())
        .add_yaxis("患病率(%)", chol_group['cardio'].round(1).tolist())
        .set_global_opts(
            title_opts=opts.TitleOpts(title="不同胆固醇等级的心脏病患病率"),
            yaxis_opts=opts.AxisOpts(name="患病率(%)", max_=100),
            tooltip_opts=opts.TooltipOpts(formatter="{b}: {c}%")
        )
    )

    """葡萄糖水平分析"""
    gluc_map = {1: "正常", 2: "偏高", 3: "严重偏高"}
    data['gluc_label'] = data['gluc'].map(gluc_map)
    gluc_group = data.groupby('gluc_label')['cardio'].mean().reset_index()
    gluc_group['cardio'] = gluc_group['cardio'] * 100
    ordered_labels = ['正常', '偏高', '严重偏高']
    gluc_group = gluc_group.set_index('gluc_label').reindex(ordered_labels).reset_index()
    gluc_bar = (
        Bar()
        .add_xaxis(gluc_group['gluc_label'].tolist())
        .add_yaxis("患病率(%)", gluc_group['cardio'].round(1).tolist())
        .set_global_opts(
            title_opts=opts.TitleOpts(title="不同葡萄糖水平的心脏病患病率"),
            yaxis_opts=opts.AxisOpts(name="患病率(%)", max_=100),
            tooltip_opts=opts.TooltipOpts(formatter="{b}: {c}%")
        )
    )

    tab = Tab()
    tab.add(bp_bar, "血压")
    tab.add(chol_bar, "胆固醇")
    tab.add(gluc_bar, "葡萄糖")
    return tab


# 主要体征指标
def indicator_radar(data):
    # 需要的指标及其对应的中文名称
    indicators = {
        'ap_hi': '收缩压',
        'ap_lo': '舒张压',
        'weight': '体重',
        'height': '身高'
    }

    # 计算每项指标的均值
    means = data[list(indicators.keys())].mean()

    # 确定最大值上限（用于雷达图 schema）
    max_vals = {
        '收缩压': 200,
        '舒张压': 150,
        '体重': 150,
        '身高': 210
    }

    # 使用中文指标名称创建schema
    schema = [
        opts.RadarIndicatorItem(name=indicators[key], max_=max_vals[indicators[key]])
        for key in indicators
    ]

    # 获取对应的均值
    values = [round(means[key], 1) for key in indicators]

    # 创建雷达图并设置布局为居中，同时向下平移
    radar = (
        Radar(init_opts=opts.InitOpts(
            width="800px",
            height="600px",  # 增加高度为图表向下平移提供空间
            renderer="svg",
            # bg_color="rgba(255,255,255,1)",  # 白色背景
            page_title="体征指标雷达图"
        ))
        .add_schema(
            schema=schema,
            splitarea_opt=opts.SplitAreaOpts(
                is_show=True,
                areastyle_opts=opts.AreaStyleOpts(opacity=0.1)
            ),
            shape="circle",
            center=["50%", "55%"]  # 垂直方向设置为60%使雷达图向下平移
        )
        .add(
            series_name="平均体征值",
            data=[values],
            areastyle_opts=opts.AreaStyleOpts(opacity=0.3, color="#5470C6"),
            linestyle_opts=opts.LineStyleOpts(width=2, color="#5470C6"),
            label_opts=opts.LabelOpts(
                is_show=True,
                formatter="{c}",
                color="#5470C6",
                position="top",
                font_size=12
            )
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(
                title="主要体征指标雷达图",
                subtitle="各项体征值的平均值对比",
                pos_left="center",
                padding=[0, 0, 20, 0],  # 增加标题下方的间距
                title_textstyle_opts=opts.TextStyleOpts(
                    font_size=18,
                    font_weight="bold",
                    color="#333"
                ),
                subtitle_textstyle_opts=opts.TextStyleOpts(
                    font_size=14,
                    color="#666"
                )
            ),
            tooltip_opts=opts.TooltipOpts(formatter="{b}: {c}"),
            legend_opts=opts.LegendOpts(is_show=False),
            # 为标题区域添加更多空间
            graphic_opts=[
                opts.GraphicGroup(
                    graphic_item=opts.GraphicItem(
                        left="center",
                        top=10,
                        z=100
                    )
                )
            ]
        )
    )

    return radar


# 生活习惯与心脏病柱状图
def lifestyle_bar(data):
    tab = Tab()
    habits = {'smoke': '吸烟', 'alco': '饮酒', 'active': '运动'}

    for h in habits:
        grouped = data.groupby(h)['cardio'].mean().reset_index()
        x = ['否', '是'] if 0 in grouped[h].values else ['是']
        y = (grouped['cardio'] * 100).round(2).tolist()
        bar = (
            Bar()
            .add_xaxis(x)
            .add_yaxis("患病率(%)", y)
            .set_global_opts(
                title_opts=opts.TitleOpts(title=f"{h.upper()} 与心脏病关系"),
                xaxis_opts=opts.AxisOpts(name=h),
                yaxis_opts=opts.AxisOpts(name="患病率(%)")
            )
        )
        tab.add(bar, habits[h])
    return tab


# 特征相关性热力图
def feature_correlation_heatmap(data):
    features = ['age', 'height', 'weight', 'ap_hi', 'ap_lo', 'cholesterol', 'gluc', 'cardio']
    corr = data[features].corr().round(2)
    x_axis = y_axis = corr.columns.tolist()
    data_list = [[i, j, corr.iloc[i, j]] for i in range(len(x_axis)) for j in range(len(y_axis))]
    heatmap = (
        HeatMap()
        .add_xaxis(x_axis)
        .add_yaxis("相关系数", y_axis, data_list, label_opts=opts.LabelOpts(is_show=True, formatter="{c}"))
        .set_global_opts(
            title_opts=opts.TitleOpts(title="特征相关性热力图"),
            visualmap_opts=opts.VisualMapOpts(min_=-1, max_=1, is_calculable=True)
        )
    )
    return heatmap
